package com.example.springboottest.example.io.redirect.appserver.nio2;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.concurrent.*;

/**
 * 支持多个客户端连接，均为非阻塞
 * 但是在链接服务器的时候，还是存在阻塞情况
 * AsynchronousSocketChannel channel = future.get();
 */
public class NIO2Server2 {
    private AsynchronousServerSocketChannel serverChannel;

    class ServerCompletionHandler implements CompletionHandler<AsynchronousSocketChannel, Void> {
        private AsynchronousServerSocketChannel serverChannel;
        private ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
        private CharBuffer charBuffer;
        private CharsetDecoder decoder = Charset.defaultCharset().newDecoder();

        public ServerCompletionHandler(AsynchronousServerSocketChannel serverChannel) {
            this.serverChannel = serverChannel;
        }

        @Override
        public void completed(AsynchronousSocketChannel result, Void attachment) {
            System.out.println("completed方法开始" + Thread.currentThread().getName());
            System.out.println(serverChannel.hashCode());
            System.out.println(this.getClass().toString());
            //立即接收下一个请求
            serverChannel.accept(null, this);
            try {
                //读取当前请求
                while (result.read(buffer).get() != -1) {
                    buffer.flip();
                    charBuffer = decoder.decode(buffer);
                    String request = charBuffer.toString().trim();
                    System.out.println("客户端请求" + request);

                    ByteBuffer outBuffer = ByteBuffer.wrap(("请求" + request + "收到").getBytes());
                    //将响应输出到客户端
                    result.write(outBuffer).get();
                    if (buffer.hasRemaining())
                        buffer.compact();
                    else
                        buffer.clear();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                System.out.println("completed方法结束" + Thread.currentThread().getName());
                try {
                    result.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void failed(Throwable exc, Void attachment) {
            serverChannel.accept(null, this);
            throw new RuntimeException("连接失败");
        }
    }

    public void init() throws Exception {
        //创建AsynchronousServerSocketChannel
        serverChannel = AsynchronousServerSocketChannel.open();

        if (serverChannel.isOpen()) {
            serverChannel.setOption(StandardSocketOptions.SO_RCVBUF, 4 * 1024);
            serverChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
            //绑定端口
            serverChannel.bind(new InetSocketAddress("127.0.0.1", 8080));
        } else
            throw new RuntimeException("通道未打开！");
    }

    public void start() throws Exception {
        System.out.println("等待客户端请求......");
        //接收客户端请求,指定CompletionHandler，会单独启动一个线程，类似NIO2Server的线程池
        serverChannel.accept(null, new ServerCompletionHandler(serverChannel));
        while (true) {
            TimeUnit.MINUTES.sleep(5);
        }

    }


    public static void main(String[] args) throws Exception {
        NIO2Server2 server = new NIO2Server2();
        server.init();
        server.start();
    }
}
